package support;

import cn.hutool.core.bean.BeanUtil;
import com.bugstack.springframework.beans.BeansException;
import com.bugstack.springframework.beans.PropertyValue;
import com.bugstack.springframework.beans.PropertyValues;
import com.bugstack.springframework.beans.factory.config.BeanDefinition;
import com.bugstack.springframework.beans.factory.config.BeanReference;


import java.lang.reflect.Constructor;


/**
 * 在这个类中具体的去实例化Bean,该类主要是进行bean的自动装配和创建
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    //传入实例化对象函数
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();


    /**
     * createBean 方法用于创建 Bean 实例。
     * 首先调用 createBeanInstance 方法创建 Bean 实例。
     * 然后调用 applyPropertyValues 方法给 Bean 填充属性。
     * 最后将创建的 Bean 实例添加到单例缓存中，并返回该实例。
     * @param beanName
     * @param beanDefinition
     * @param args
     * @return
     */
    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object [] args) {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);
            applyPropertyValues(beanName,bean,beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        addSingleton(beanName, bean);
        return bean;
    }


    //使用构造器创建bean的实例
    public Object createBeanInstance(BeanDefinition beanDefinition,String name,Object [] args){
        Constructor constructor = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
            Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
            //它遍历 Bean 类的所有声明的构造函数，并选择一个参数数量与 args 长度匹配的构造函数。
            for (Constructor<?> declaredConstructor : declaredConstructors) {
                if (null != args && declaredConstructor.getParameterTypes().length == args.length) {
                    constructor = declaredConstructor;
                    break;
                }
            }
            return getInstantiationStrategy().instantiate(beanDefinition,name,constructor,args);//返回实例化对象
    }

    /**
     *Bean 属性填充
     * @param beanName bean的名字，用于标识当前正在处理的bean
     * @param bean 当前bean的实例，属性值被设置到这个实例中
     * @param beanDefinition 包含了bean的属性值和类型信息
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition){
        PropertyValues propertyValues = beanDefinition.getPropertyValues();//获取当前bean的属性值
        for (PropertyValue propertyValue:propertyValues.getPropertyValues()){
            String name = propertyValue.getName();
            Object value = propertyValue.getValue();

            if(value instanceof BeanReference){//检查 value 是否是 BeanReference 类型。如果是，表示这是一个对其他 Bean 的引用。
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getBeanName());//如果 value 是 BeanReference，则调用 getBean(beanReference.getBeanName()) 方法来获取实际的 Bean 实例，并将 value 更新为这个实例。

            }
            //这个方法的主要目的是将指定的值 (value) 设置到目标对象 (bean) 的指定字段 (name) 上。下面详细解释一下这个方法的作用和实现细节。
            BeanUtil.setFieldValue(bean,name,value);//设置bean这个对象的name属性上的值是value
        }
    }

    //调用实例化对象函数
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}
